package net.roobook.gateway.filter;

import com.netflix.zuul.context.RequestContext;
import lombok.extern.slf4j.Slf4j;
import net.roobook.common.entity.RoobookResponse;
import net.roobook.common.utils.RoobookUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cloud.netflix.zuul.filters.post.SendErrorFilter;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;

import javax.servlet.http.HttpServletResponse;

/**
 * @Author Roobook
 * @description 自定义Zuul异常处理
 * @date 2022/4/8
 */
@Slf4j
@Component
public class RoobookGatewayErrorFilter extends SendErrorFilter {

    @Override
    public Object run() {
        try {
            RoobookResponse roobookResponse = new RoobookResponse();
            // 通过RequestContext获取到当前请求上下文
            RequestContext ctx = RequestContext.getCurrentContext();
            // 通过请求上下文可以获取到当前请求的服务名称serviceId和当前请求的异常对象ExceptionHolder
            String serviceId = (String) ctx.get(FilterConstants.SERVICE_ID_KEY);
            ExceptionHolder exception = findZuulException(ctx.getThrowable());
            // 通过异常对象我们可以继续获取到异常内容
            String errorCause = exception.getErrorCause();
            Throwable throwable = exception.getThrowable();
            String message = throwable.getMessage();
            message = StringUtils.isBlank(message) ? errorCause : message;
            // 根据不同的异常内容我们可以自定义想要的响应
            roobookResponse = resolveExceptionMessage(message, serviceId, roobookResponse);

            HttpServletResponse response = ctx.getResponse();
            RoobookUtil.makeResponse(
                    response, MediaType.APPLICATION_JSON_UTF8_VALUE,
                    HttpServletResponse.SC_INTERNAL_SERVER_ERROR, roobookResponse
            );
            log.error("Zull sendError：{}", roobookResponse.getMessage());
        } catch (Exception ex) {
            log.error("Zuul sendError", ex);
            ReflectionUtils.rethrowRuntimeException(ex);
        }
        return null;
    }

    /**
     * 根据不同的异常内容我们可以自定义想要的响应
     * @Author Roobook
     * @date 2022/4/8
     * @param message, serviceId, roobookResponse
     * @return net.roobook.common.entity.RoobookResponse
     */
    private RoobookResponse resolveExceptionMessage(String message, String serviceId, RoobookResponse roobookResponse) {
        if (StringUtils.containsIgnoreCase(message, "time out")) {
            return roobookResponse.message("请求" + serviceId + "服务超时");
        }
        if (StringUtils.containsIgnoreCase(message, "forwarding error")) {
            return roobookResponse.message(serviceId + "服务不可用");
        }
        return roobookResponse.message("Zuul请求" + serviceId + "服务异常");
    }
}